package com.auth.web.auth;

import com.auth.exception.NoAuthException;
import com.auth.token.app.AppTokenClient;
import com.auth.token.app.UserInfo;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 认证拦截器
 *
 * @author: 王霄
 * @date: 2022/1/20 21:32
 */
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Resource
    private AppTokenClient appTokenClient;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod method)) {
            return true;
        }

        //判断是否需要登录
        if (!needLogin(method)) {
            return true;
        }

        //校验token
        String token = getToken(request);
        if (!StringUtils.hasText(token)) {
            throw new NoAuthException("未认证");
        }

        auth(token);

        //放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        UserContext.clear();
    }

    private void auth(String token) {
        UserInfo userInfo = appTokenClient.getData(token);
        if (userInfo == null) {
            throw new NoAuthException("无效的token: " + token);
        }
        UserContext.setUserInfo(userInfo);
    }

    /**
     * 如果存放token的方式发生变更，修改此方法的逻辑就好
     */
    private String getToken(HttpServletRequest request) {
        return request.getHeader("token");
    }

    private boolean needLogin(HandlerMethod method) {

        // 方法上有注解以方法上的注解为准。匿名访问优先级最高
        if (method.getMethodAnnotation(NotLogin.class) != null) {
            return false;
        }
        if (method.getMethodAnnotation(MustLogin.class) != null) {
            return true;
        }

        // 方法上没有注解，看类上有没有注解。匿名访问优先级最高
        Class<?> beanType = method.getBeanType();
        if (beanType.getAnnotation(NotLogin.class) != null) {
            return false;
        }

        if (beanType.getAnnotation(MustLogin.class) != null) {
            return true;
        }

        //什么都没有就不需要认证
        return false;
    }
}
